package drds.plus.repository.mysql.handler;

import drds.plus.executor.ExecuteContext;
import drds.plus.executor.command_handler.CommandHandler;
import drds.plus.executor.command_handler.CommandHandlerFactory;
import drds.plus.executor.command_handler.query.MergeQueryHandler;
import drds.plus.executor.command_handler.query.join.IndexBlockNestedtLoopJoinHandler;
import drds.plus.executor.command_handler.query.join.IndexNestedLoopJoinHandler;
import drds.plus.executor.command_handler.query.join.SortMergeJoinHandler;
import drds.plus.sql_process.abstract_syntax_tree.execute_plan.ExecutePlan;
import drds.plus.sql_process.abstract_syntax_tree.execute_plan.dml.IPut;
import drds.plus.sql_process.abstract_syntax_tree.execute_plan.dml.PutType;
import drds.plus.sql_process.abstract_syntax_tree.execute_plan.query.Join;
import drds.plus.sql_process.abstract_syntax_tree.execute_plan.query.JoinStrategy;
import drds.plus.sql_process.abstract_syntax_tree.execute_plan.query.MergeQuery;
import drds.plus.sql_process.abstract_syntax_tree.execute_plan.query.QueryWithIndex;


public class CommandHandlerFactoryImpl implements CommandHandlerFactory {

    protected QueryMyHandler condensableJoinHandler;
    protected CommandHandler insertHandler;
    protected CommandHandler updateHandler;
    protected CommandHandler deleteHandler;
    protected CommandHandler replaceHandler;
    protected CommandHandler queryHandler;
    protected CommandHandler mergeHandler;
    protected CommandHandler indexNestLoopJoinHandler;
    protected CommandHandler indexBlockNestedtLoopJoinHandler;
    protected CommandHandler sortMergeJoinHandler;

    public CommandHandlerFactoryImpl() {
        insertHandler = new InsertMyHandler();
        updateHandler = new UpdateMyHandler();
        deleteHandler = new DeleteMyHandler();
        replaceHandler = new ReplaceMyHandler();
        queryHandler = new QueryMyHandler();
        mergeHandler = new MergeQueryHandler();
        indexNestLoopJoinHandler = new IndexNestedLoopJoinHandler();
        indexBlockNestedtLoopJoinHandler = new IndexBlockNestedtLoopJoinHandler();
        sortMergeJoinHandler = new SortMergeJoinHandler();
        condensableJoinHandler = new QueryMyHandler();

    }

    public CommandHandler getCommandHandler(ExecuteContext executeContext, ExecutePlan executePlan) {

        if (executePlan instanceof QueryWithIndex) {
            return queryHandler;
        } else if (executePlan instanceof MergeQuery) {
            return mergeHandler;
        } else if (executePlan instanceof Join) {
            boolean isCondensable = isCondensable(executePlan);
            if (isCondensable) {
                return condensableJoinHandler;
            }

            Join join = (Join) executePlan;
            JoinStrategy joinStrategy = join.getJoinStrategy();
            switch (joinStrategy) {
                case index_nest_loop_join:
                    return indexNestLoopJoinHandler;
                case nest_loop_join:
                    if (join.getRightNode().isSubQuery()) {
                        return indexBlockNestedtLoopJoinHandler;
                    } else {
                        // mysql支持非主键的查询，所以即使是nest_loop，也可以选择index的模式
                        return indexNestLoopJoinHandler;
                    }
                case sort_merge_join:
                    return sortMergeJoinHandler;
                default:
                    throw new IllegalArgumentException("should not be here");
            }
        } else if (executePlan instanceof IPut) {
            IPut put = (IPut) executePlan;
            PutType putType = put.getPutType();
            switch (putType) {
                case replace:
                    return replaceHandler;
                case insert:
                    return insertHandler;
                case delete:
                    return deleteHandler;
                case update:
                    return updateHandler;
                default:
                    throw new IllegalArgumentException("should not be here");
            }
        } else {
            throw new IllegalArgumentException("should not be here");
        }
    }

    private boolean isCondensable(ExecutePlan executePlan) {
        Join join = (Join) executePlan;
        String leftNodeDataNodeId = join.getLeftNode().getDataNodeId();
        String rightNodeDataNodeId = join.getRightNode().getDataNodeId();
        if (leftNodeDataNodeId == null || rightNodeDataNodeId == null) {
            return false;
        } else if (!leftNodeDataNodeId.equals(rightNodeDataNodeId)) {
            return false;
        }

        if (join.getLeftNode() instanceof MergeQuery || join.getRightNode() instanceof MergeQuery) {
            return false;
        }
        boolean leftJoin = true;
        boolean rightJoin = true;
        if (join.getLeftNode() instanceof Join) {
            leftJoin = isCondensable(join.getLeftNode());
        }
        if (join.getRightNode() instanceof Join) {
            rightJoin = isCondensable(join.getRightNode());
        }

        return leftJoin & rightJoin;
    }
}
